﻿#include "XyNetCompiler/ServiceParser.h"
#include "XyNetCompiler/ProtoCodeGenerator.h"
#include "XyNetCompiler/CppCodeGenerator.h"
#include "XyNetCompiler/CSharpCodeGenerator.h"
#include <google/protobuf/compiler/command_line_interface.h>
#include <google/protobuf/compiler/cpp/cpp_generator.h>
#include <google/protobuf/compiler/csharp/csharp_generator.h>

#if defined(_MSC_VER)
#	pragma comment(lib, "CryptoPP.lib")
#	pragma comment(lib, "protobuf.lib")
#endif

using namespace XyNet;

// 负责清理google分配的内存
class ProtobufCleaner
{
public:
	~ProtobufCleaner()
	{
		google::protobuf::ShutdownProtobufLibrary();
	}
} _protobufCleaner;

// 服务和方法用大小写，参数用小写+下划线
int main(int argc, char* argv[])
{
#ifndef _DEBUG
	try
	{
#endif
		cout << argc << endl;
		for (int i = 0; i < argc; ++i)
			cout << argv[i] << endl;

		filesystem::path parseDirPath;	// 需要解析的目录路径
		if (argc == 1)
			parseDirPath = filesystem::current_path();
		else
			parseDirPath = argv[1];

#if 1
		// 测试用
		parseDirPath = "../../../src/XyNet/Protocol";
		//parseDirPath = "../../../src/XyNetTest/Protocol";
#endif

		//auto p = filesystem::absolute(parseDirPath);
		parseDirPath = filesystem::canonical(parseDirPath);
		filesystem::current_path(parseDirPath);

		ServiceParser parser;
		parser.addCodeGenerator(std::make_shared<ProtoCodeGenerator>());
		parser.addCodeGenerator(std::make_shared<CppCodeGenerator>());
		parser.addCodeGenerator(std::make_shared<CSharpCodeGenerator>());

		// 解析service文件		
		for (filesystem::directory_iterator iter(parseDirPath);
			iter != filesystem::directory_iterator(); ++iter)
		{
			const auto& childPath = iter->path();
			if (childPath.extension() == ".service")
				parser.parse(childPath);
		}

		// 解析proto文件
		for (filesystem::directory_iterator iter(parseDirPath);
			iter != filesystem::directory_iterator(); ++iter)
		{
			const auto& childPath = iter->path();
			if (childPath.extension() == ".proto")
			{
				google::protobuf::compiler::CommandLineInterface cli;
				cli.AllowPlugins("protoc-");

				google::protobuf::compiler::cpp::CppGenerator cpp_generator;
				cli.RegisterGenerator("--cpp_out", "--cpp_opt", &cpp_generator,
					"Generate C++ header and source.");
				google::protobuf::compiler::csharp::Generator csharp_generator;
				cli.RegisterGenerator("--csharp_out", "--csharp_opt", &csharp_generator,
					"Generate C# source file.");

				int gc = 5;
				char* gv[5];
				string cppOutArg = "--cpp_out=" + parseDirPath.string() + "/cpp";
				string csharpOutArg = "--csharp_out=" + parseDirPath.string() + "/csharp";
				string protoPathArg = /*"--proto_path="*/"-I=" + parseDirPath.string();
				string protoFileName = childPath.string();

				gv[0] = argv[0];
				gv[1] = (char*)cppOutArg.c_str();
				gv[2] = (char*)csharpOutArg.c_str();
				gv[3] = (char*)protoPathArg.c_str();
				gv[4] = (char*)protoFileName.c_str();
				int result = cli.Run(gc, gv);
				if (result != 0)
					return result;
			}
		}

		return 0;
#ifndef _DEBUG
	}
	catch (const exception& e)
	{
		cerr << e.what() << endl;
	}
#endif
}